/**
 * @brief util函数
 */

#ifndef __UTIL_H__
#define __UTIL_H__

#include <sys/types.h>
#include <cstdint>
#include <sys/time.h>
#include <cxxabi.h> // for abi::__cxa_demangle()
#include <string>
#include <vector>
#include <iostream>

// 获取线程ID
pid_t GetThreadId();

// 获取协程ID
uint64_t GetFiberId();

// 获取当前启动的毫秒数,参考clock_gettime(2) 使用CLOCK_MONOTONIC_RAW
uint64_t GetElapsedMS();

// 获取线程名称,参考pthread_getname_np(3)
std::string GetThreadName();

// 设置线程名称,参考pthread_setname_np(3)
// 线程名称不能超过16字节,包括结尾的'\0'字符

void SetThreadName(const std::string &name);

// 获取当前的调用栈
// bt 保存调用栈
// size 最多返回次数
// skip 跳过栈顶顶层数
void Backtrace(std::vector<std::string> &bt, int size = 64, int skip = 1);

// 获取当前栈信息的字符串
// size 栈的最大层数
// skip 跳过栈顶顶层数
// prefix 栈信息前输出的内容

std::string BacktraceToString(int size = 64, int skip = 2, const std::string &prefix = "");

// 获取当前时间的毫秒
uint64_t GetCurrentMS();

// 获取当前时间的微妙
uint64_t GetCurrentNS();

// 字符串转大写
std::string ToUpper(const std::string &name);

// 字符串转小写
std::string ToLower(const std::string &name);

// 日期时间转字符串
std::string Time2Str(time_t ts = time(0), const std::string &format = "%Y-%m-%d %H:%M:%S");

// 字符串转日期
time_t Str2Time(const char *str, const char *format = "%Y-%m-%d %H:%M:%S");

// 文件系统操作类
class FSUtil
{
public:
    // 递归列举指定目录下所有指定后缀的常规文件,如果不指定,则遍历所有文件,返回文件名带路径
    static void ListAllFile(std::vector<std::string> &files, const std::string &path, const std::string &subfix);

    // 创建路径,相当于mkdir -p
    static bool Mkdir(const std::string &dirname);

    // 判断指定pid文件指定的pid是否正在运行,使用kill(pid,0)的方式判断
    // pidfile 保存进程号的文件
    static bool isRunningPidfile(const std::string &pidfile);

    // 删除文件或路径
    static bool Rm(const std::string &path);

    // 移动文件或路径,内部实现是先Rm(to),再rename(from,to),参考rename
    static bool Mv(const std::string &from, const std::string &to);

    // 返回绝对路径,参考realpath(3)
    // 路径这个的符号链接会被解析成实际的路径,删除多余的'.' '..'和'/'
    static bool RealPath(const std::string &path, std::string &rpath);

    // 创建符号链接，参考symlink
    static bool Symlink(const std::string &from, const std::string &to);

    // 删除文件,参考unlink
    static bool Unlink(const std::string &filename, bool exist = false);

    // 返回文件,即路径中最后一个/前面部分,不包括/本身,如果未找到,则返回filename
    static std::string Dirname(const std::string &filename);

    // 返回文件名,即路径中最后一个/后面部分
    static std::string Basename(const std::string &filename);

    // 以只读方式打开文件
    static bool OpenForRead(std::ifstream &ifs, const std::string &filename, std::ios_base::openmode mode);

    // 以只写方式打卡文件
    static bool OpenForWrite(std::ofstream &ofs, const std::string &filename, std::ios_base::openmode mode);
};

/**
 * @brief 类型转换
 */

class TypeUtil
{
public:
    // 转字符,返回*str.begin()
    static int8_t Tochar(const std::string &str);
    // atoi
    static uint64_t Atoi(const std::string &str);
    // atof
    static double Atof(const std::string &str);
    // 返回str[0]
    static uint8_t Tochar(const char *str);
    // atoi
    static uint64_t Atoi(const char *str);
    // atof
    static double Atof(const char *str);
};

/**
 * @brief 获取T类型的字符串
 */
template <class T>
const char *TypeToName()
{
    static const char *s_name = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
    return s_name;
}

/**
 * @brief 字符串辅助类
 */

class StringUtil
{
public:
    // printf 风格的字符串转化,返回格式化后的string
    static std::string Format(const char *fmt, ...);
    // vprintf 风格的字符串转化,返回格式化后的string
    static std::string Formatv(const char *fmt, va_list ap);

    // url解码
    static std::string UrlEncode(const std::string &str, bool convert_plus_to_space = true);

    // url编码
    static std::string UrlDeconde(const std::string &str, bool convert_space_to_plus = true);

    // 移除字符串首尾的指定字符串
    static std::string Trim(const std::string &str, const std::string &delimit = "\t\r\n");
    // 移除字符串首部的指定字符串
    static std::string Trimleft(const std::string &str, const std::string &delimit = "\t\r\n");
    // 移除字符串尾部的指定字符串
    static std::string TrimRight(const std::string &str, const std::string &delimit = "\t\r\n");

    // 宽字符串转字符串
    static std::string WStringToString(const std::wstring &ws);
    // 字符串转宽字符串
    static std::wstring StringToWstring(const std::string &str);
};

#endif